package cn.lblbc.lib.download

import android.os.Build
import android.util.Log
import cn.lblbc.lib.download.db.bean.DbDownloadPartInfo
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.net.HttpURLConnection
import java.net.URL
import java.security.MessageDigest
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue


fun readContentLength(connection: HttpURLConnection): Long {
    var fileSize = -1L
    fileSize = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        connection.contentLengthLong
    } else {
        connection.contentLength.toLong()
    }
    return fileSize
}

fun setHttpHeaders(urlConnection: HttpURLConnection, start: Long, end: Long, downUrl: String) {
    val headers: MutableMap<String, String> = HashMap()
    headers["Accept"] = "*/*"
    headers["Accept-Language"] = "en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4,ja;q=0.2"
    headers["Connection"] = "keep-alive"
    headers["Referer"] = downUrl
    headers["Charset"] = "UTF-8"
    headers["Accept-Ranges"] = "bytes"
    headers["Range"] = "bytes=" + start + "-" + if (end > start) java.lang.Long.valueOf(end) else ""
    headers["Content-Type"] = "application/vnd.android.package-archive"

    headers.forEach {
        urlConnection.setRequestProperty(it.key, it.value)
    }
}

fun getHttpFileContentLength(urlStr: String, result: Result): Long {
    var connection: HttpURLConnection? = null
    var contentLength = -1L
    try {
        val url = URL(urlStr)
        connection = url.openConnection() as HttpURLConnection
        connection.requestMethod = "GET"
        connection.connectTimeout = 8000
        connection.readTimeout = 5000
        val responseCode: Int = connection.responseCode
        if (responseCode == 200) {
            contentLength = readContentLength(connection)
        } else {
            result.code = responseCode
        }
    } catch (e: Exception) {
        result.code = -1
        result.msg = e.message ?: ""
        Log.e("Utils", Log.getStackTraceString(e))
    } finally {
        connection?.disconnect()
    }
    return contentLength
}

fun generateDownloadApkName(): String {
    return getUUID() + ".apk"
}

fun getUUID(): String {
    return UUID.randomUUID().toString().replace("-", "")
}

/** md5加密 */
fun md5(content: String): String {
    val hash = MessageDigest.getInstance("MD5").digest(content.toByteArray())
    val hex = StringBuilder(hash.size * 2)
    for (b in hash) {
        var str = Integer.toHexString(b.toInt())
        if (b < 0x10) {
            str = "0$str"
        }
        hex.append(str.substring(str.length - 2))
    }
    return hex.toString()
}

fun fillFile(file: File?, contentLength: Long): String? {
    return try {
        val randomAccessFile = RandomAccessFile(file, "rw")
        randomAccessFile.setLength(contentLength)
        randomAccessFile.close()
        null
    } catch (e: java.lang.Exception) {
        val errorMsg = e.message + "."
        e.message?.let { Log.e("Utils", it) }
        errorMsg
    }
}

fun calcParts(fileSize: Long, partSize: Long, taskId: String): List<DbDownloadPartInfo> {
    val parts = mutableListOf<DbDownloadPartInfo>()
    var partCount = fileSize / partSize
    (0 until partCount).forEach {
        parts.add(DbDownloadPartInfo(taskId = taskId, partStart = partSize * it, partEnd = partSize * (it + 1) - 1))
    }
    if (fileSize % partSize != 0L) {
        parts.add(DbDownloadPartInfo(taskId = taskId, partStart = partSize * partCount, partEnd = fileSize - 1))
    }
    return parts
}

fun convertToQueue(list: List<DbDownloadPartInfo>): ConcurrentLinkedQueue<DbDownloadPartInfo> {
    val parts = ConcurrentLinkedQueue<DbDownloadPartInfo>()
    list.forEach {
        parts.add(it)
    }
    return parts
}

fun calcDownloadSize(contentLength: Long, partQueue: ConcurrentLinkedQueue<DbDownloadPartInfo>): Long {
    val list: MutableList<DbDownloadPartInfo> = ArrayList()
    list.addAll(partQueue)
    var size: Long = 0
    for (i in list.indices) {
        val part: DbDownloadPartInfo = list[i]
        size += part.partEnd - part.partStart + 1 - part.partWritten
    }
    return contentLength - size
}

fun closeStream(raf: RandomAccessFile?) {
    raf?.let {
        try {
            raf.close()
        } catch (e: IOException) {
            Log.e("Utils", Log.getStackTraceString(e))
        }
    }
}